// XMLReaderAdapter.java - adapt an SAX2 XMLReader to a SAX1 Parser
// http://www.saxproject.org
// Written by David Megginson
// NO WARRANTY!  This class is in the public domain.
// $Id: XMLReaderAdapter.java,v 1.9 2004/04/26 17:34:35 dmegginson Exp $

package org.xml.sax.helpers;

import java.io.IOException;
import java.util.Locale;
import org.xml.sax.AttributeList;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.DocumentHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.Parser;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.XMLReader;


/**
 * 将SAX2 XMLReader调整为SAX1解析器
 *
 *这个类包装了一个SAX2 {@link org.xml.sax.XMLReader XMLReader} ，并使其充当SAX1 {@link org.xml.sax.Parser Parser}。
 *
 * XMLReader必须支持http：xml.org/sax/features/namespace-prefixes属性值为true，
 * 否则解析将失败{@link org.xml.sax.SAXException SAXException}
 *
 * 如果XMLReader支持http：xml.org/sax/features/namespaces属性的值为false，那么将用于提高效率。
 *
 * @since SAX 2.0
 * @author David Megginson
 * @version 2.0.1 (sax2r2)
 * @see org.xml.sax.Parser
 * @see org.xml.sax.XMLReader
 */
public class XMLReaderAdapter implements Parser, ContentHandler
{


    ////////////////////////////////////////////////////////////////////
    // 构造函数.
    ////////////////////////////////////////////////////////////////////


    /**
     * 创建一个新的适配器。
     *
     * 使用“org.xml.sax.driver”属性来定位要嵌入的SAX2驱动程序。
     *
     * @exception org.xml.sax.SAXException 如果嵌入式驱动程序无法实例化，或者未指定org.xml.sax.driver属性。
     */
    public XMLReaderAdapter ()
      throws SAXException
    {
    setup(XMLReaderFactory.createXMLReader());
    }


    /**
     * 创建一个新的适配器。
     *
     * 创建一个新的适配器，包装在一个SAX2 XMLReader中。 适配器将使XMLReader像SAX1解析器一样工作。
     *
     * @param xmlReader SAX2 XMLReader包装。
     * @exception java.lang.NullPointerException If the argument is null.
     */
    public XMLReaderAdapter (XMLReader xmlReader)
    {
    setup(xmlReader);
    }



    /**
     * 内部设置。
     *
     * @param xmlReader The embedded XMLReader.
     */
    private void setup (XMLReader xmlReader)
    {
    if (xmlReader == null) {
        throw new NullPointerException("XMLReader must not be null");
    }
    this.xmlReader = xmlReader;
    qAtts = new AttributesAdapter();
    }



    ////////////////////////////////////////////////////////////////////
    // Implementation of org.xml.sax.Parser.
    ////////////////////////////////////////////////////////////////////


    /**
     * 设置错误报告的locale设置
     *
     *这在SAX2中不被支持，并且总会抛出一个异常。
     * @param locale the locale for error reporting.
     * @see org.xml.sax.Parser#setLocale
     * @exception org.xml.sax.SAXException Thrown unless overridden.
     */
    public void setLocale (Locale locale)
    throws SAXException
    {
    throw new SAXNotSupportedException("setLocale not supported");
    }


    /**
     * 注册实体解析器
     *
     * @param resolver The new resolver.
     * @see org.xml.sax.Parser#setEntityResolver
     */
    public void setEntityResolver (EntityResolver resolver)
    {
    xmlReader.setEntityResolver(resolver);
    }


    /**
     * 注册DTD事件处理程序
     *
     * @param handler The new DTD event handler.
     * @see org.xml.sax.Parser#setDTDHandler
     */
    public void setDTDHandler (DTDHandler handler)
    {
    xmlReader.setDTDHandler(handler);
    }


    /**
     * 注册SAX1文档事件处理程序。
     *
     * 请注意，SAX1文档处理程序没有名称空间支持。
     *
     * @param handler The new SAX1 document event handler.
     * @see org.xml.sax.Parser#setDocumentHandler
     */
    public void setDocumentHandler (DocumentHandler handler)
    {
    documentHandler = handler;
    }


    /**
     * 注册错误事件处理程序。
     *
     * @param handler The new error event handler.
     * @see org.xml.sax.Parser#setErrorHandler
     */
    public void setErrorHandler (ErrorHandler handler)
    {
    xmlReader.setErrorHandler(handler);
    }


    /**
     * 解析文档。
     *
     * 如果嵌入式XMLReader不支持http：xml.org/sax/features/namespace-prefixes属性，则此方法将引发异常
     *
     * @param systemId 文档的绝对URL
     * @exception java.io.IOException 如果读取文档的原始内容有问题
     * @exception org.xml.sax.SAXException 如果在处理文档时出现问题
     * @see #parse(org.xml.sax.InputSource)
     * @see org.xml.sax.Parser#parse(java.lang.String)
     */
    public void parse (String systemId)
    throws IOException, SAXException
    {
    parse(new InputSource(systemId));
    }


    /**
     * 解析文档。
     *
     * 如果嵌入式XMLReader不支持http：xml.org/sax/features/namespace-prefixes属性，则此方法将引发异常。
     *
     * @param input 文档的输入源。
     * @exception java.io.IOException 如果读取文档的原始内容有问题t.
     * @exception org.xml.sax.SAXException 如果在处理文档时出现问题。
     * @see #parse(java.lang.String)
     * @see org.xml.sax.Parser#parse(org.xml.sax.InputSource)
     */
    public void parse (InputSource input)
    throws IOException, SAXException
    {
    setupXMLReader();
    xmlReader.parse(input);
    }


    /**
     * 设置XML阅读器。
     */
    private void setupXMLReader ()
    throws SAXException
    {
    xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
    try {
        xmlReader.setFeature("http://xml.org/sax/features/namespaces",
                             false);
    } catch (SAXException e) {
        // NO OP: it's just extra information, and we can ignore it
    }
    xmlReader.setContentHandler(this);
    }



    ////////////////////////////////////////////////////////////////////
    // Implementation of org.xml.sax.ContentHandler.
    ////////////////////////////////////////////////////////////////////


    /**
     * 设置文档定位器。
     *
     * @param locator The document locator.
     * @see org.xml.sax.ContentHandler#setDocumentLocator
     */
    public void setDocumentLocator (Locator locator)
    {
    if (documentHandler != null)
        documentHandler.setDocumentLocator(locator);
    }


    /**
     *启动文档事件。
     * @exception org.xml.sax.SAXException 客户可能会引起处理异常。
     * @see org.xml.sax.ContentHandler#startDocument
     */
    public void startDocument ()
    throws SAXException
    {
    if (documentHandler != null)
        documentHandler.startDocument();
    }


    /**
     * ：结束文档事件。
     * @exception org.xml.sax.SAXException 客户可能会引起处理异常。
     * @see org.xml.sax.ContentHandler#endDocument
     */
    public void endDocument ()
    throws SAXException
    {
    if (documentHandler != null)
        documentHandler.endDocument();
    }


    /**
     * 调整SAX2开始前缀映射事件。
     *
     * @param prefix 被映射的前缀。
     * @param uri 要映射到的名称空间URI
     * @see org.xml.sax.ContentHandler#startPrefixMapping
     */
    public void startPrefixMapping (String prefix, String uri)
    {
    }


    /**
     * 调整SAX2结束前缀映射事件。
     *
     * @param prefix 被映射的前缀
     * @see org.xml.sax.ContentHandler#endPrefixMapping
     */
    public void endPrefixMapping (String prefix)
    {
    }


    /**
     * 调整SAX2开始元素事件。
     *
     * @param uri 名字空间URI
     * @param localName 名称空间本地名称
     * @param qName 合格的（前缀）名称。
     * @param atts SAX2属性。
     * @exception org.xml.sax.SAXException 客户可能会引起处理异常。
     * @see org.xml.sax.ContentHandler#endDocument
     */
    public void startElement (String uri, String localName, String qName, Attributes atts)
    throws SAXException
    {
    if (documentHandler != null) {
        qAtts.setAttributes(atts);
        documentHandler.startElement(qName, qAtts);
    }
    }


    /**
     * 调整SAX2结束元素事件。
     *
     * @param uri 名字空间URI。
     * @param localName 名称空间本地名称.
     * @param qName 合格的（前缀）名称
     * @exception org.xml.sax.SAXException 客户可能会引起处理异常。
     * @see org.xml.sax.ContentHandler#endElement
     */
    public void endElement (String uri, String localName,
                String qName)
    throws SAXException
    {
    if (documentHandler != null)
        documentHandler.endElement(qName);
    }


    /**
     * 调整SAX2字符事件。
     *
     * @param ch 一组字符。
     * @param start 数组中的起始位置。
     * @param length 使用的字符数。
     * @exception org.xml.sax.SAXException 客户可能会引起处理异常。
     * @see org.xml.sax.ContentHandler#characters
     */
    public void characters (char ch[], int start, int length)
    throws SAXException
    {
    if (documentHandler != null)
        documentHandler.characters(ch, start, length);
    }


    /**
     * 调整SAX2可忽略的空白事件。
     *
     * @param ch 一组字符。
     * @param start 数组中的起始位置。
     * @param length 要使用的字符数。
     * @exception org.xml.sax.SAXException 客户可能会引起处理异常。
     * @see org.xml.sax.ContentHandler#ignorableWhitespace
     */
    public void ignorableWhitespace (char ch[], int start, int length)
    throws SAXException
    {
    if (documentHandler != null)
        documentHandler.ignorableWhitespace(ch, start, length);
    }


    /**
     * 调整SAX2处理指令事件。
     *
     * @param target 处理指令的目标。
     * @param data 处理指令的其余部分
     * @exception org.xml.sax.SAXException 客户可能会引起处理异常。
     * @see org.xml.sax.ContentHandler#processingInstruction
     */
    public void processingInstruction (String target, String data)
    throws SAXException
    {
    if (documentHandler != null)
        documentHandler.processingInstruction(target, data);
    }


    /**
     * 调整SAX2跳过的实体事件。
     *
     * @param name 被跳过的实体的名称。
     * @see org.xml.sax.ContentHandler#skippedEntity
     * @exception org.xml.sax.SAXException Throwable by subclasses.
     */
    public void skippedEntity (String name)
    throws SAXException
    {
    }



    ////////////////////////////////////////////////////////////////////
    // 内部状态。
    ////////////////////////////////////////////////////////////////////

    XMLReader xmlReader;
    DocumentHandler documentHandler;
    AttributesAdapter qAtts;



    ////////////////////////////////////////////////////////////////////
    // 内部类。
    ////////////////////////////////////////////////////////////////////


    /**
     * 内部类包装SAX1的SAX2属性对象。
     */
    static final class AttributesAdapter implements AttributeList
    {
    AttributesAdapter ()
    {
    }


    /**
     *设置嵌入的属性对象。
     *
     * @param attributes  嵌入的SAX2属性。
     */
    void setAttributes (Attributes attributes)
    {
        this.attributes = attributes;
    }


    /**
     * 返回属性的数量。
     *
     * @return 属性列表的长度
     * @see org.xml.sax.AttributeList#getLength
     */
    public int getLength ()
    {
        return attributes.getLength();
    }


    /**
     * 按位置返回属性的限定（前缀）名称。
     * @return 合格的名字。
     * @see org.xml.sax.AttributeList#getName
     */
    public String getName (int i)
    {
        return attributes.getQName(i);
    }


    /**
     * 按位置返回属性的类型。
     * @return The type.
     * @see org.xml.sax.AttributeList#getType(int)
     */
    public String getType (int i)
    {
        return attributes.getType(i);
    }


    /**
     * 返回指定位置的属性的值。
     *
     * @return The value.
     * @see org.xml.sax.AttributeList#getValue(int)
     */
    public String getValue (int i)
    {
        return attributes.getValue(i);
    }


    /**
     * 按限定（前缀）名称返回属性的类型。
     * @return The type.
     * @see org.xml.sax.AttributeList#getType(java.lang.String)
     */
    public String getType (String qName)
    {
        return attributes.getType(qName);
    }


    /**
     * 以限定（前缀）名称返回属性的值
     *
     * @return The value.
     * @see org.xml.sax.AttributeList#getValue(java.lang.String)
     */
    public String getValue (String qName)
    {
        return attributes.getValue(qName);
    }

    private Attributes attributes;
    }

}
